﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Kotonoha.Server.Dictionaries;
using Kotonoha.Server.Settings;
using Kotonoha.Server.Utils;

namespace Kotonoha.Server.Plugins {

    public delegate string PathProvider(Plugin plugin);

    public abstract class Plugin {
        private static readonly Type[] NoArguments = new Type[0];
        private static readonly object[] NoParams = new object[0];

        private string name;
        private string mask;
        private Setting settings;

        public string Name {
            [DebuggerStepThrough]
            get { return name; }
        }
         
        public string Mask {
            [DebuggerStepThrough]
            get { return mask; }
        }

        public Setting Settings {
            [DebuggerStepThrough]
            get { return settings; }
        }

        public static object Instantiate(Type t) {
            ConstructorInfo constructor = t.GetConstructor(NoArguments);
            object o = constructor.Invoke(NoParams);
            return o;
        }

        protected virtual void FillCommon(Type pluginType) {
            PluggableReaderAttribute attr = (PluggableReaderAttribute) pluginType.GetCustomAttributes(typeof(PluggableReaderAttribute), false)[0];
            name = attr.DictionaryName;
            mask = attr.FilePattern;
            settings = SettingsManager.Acquire(name);
        }

        public string GetMessage() {
            if (Settings["file"] == null) {
                return "No file specified";
            }
            return "OK";
        }
    }

    public class CharPlugin : Plugin {
        private readonly ICharDictionaryReader reader;

        private CharPlugin(ICharDictionaryReader reader) {
            this.reader = reader;
        }

        public static CharPlugin Create(Type t) {
            ICharDictionaryReader reader = Instantiate(t) as ICharDictionaryReader;
            CharPlugin plugin = new CharPlugin(reader);
            plugin.FillCommon(t);
            return plugin;
        }

        public ICharDictionary read(PathProvider provider) {
            string filename = Settings["file"] as string;
            if (filename == null) {
                string found = provider(this);
                filename = PathUtil.GetDictPath(Mask);
                ICharDictionary dic = readDic(found);
                File.Copy(found, filename, true);
                Settings["file"] = filename;
                return dic;
            }
            return readDic(filename);
        }

        private ICharDictionary readDic(string filename) {
            FileStream stream = File.OpenRead(filename);
            ICharDictionary dictionary = reader.read(stream);
            stream.Close();
            return dictionary;
        }
    }

    public class WordPlugin : Plugin {
        private readonly IWordDictionaryReader reader;

        private WordPlugin(IWordDictionaryReader reader) {
            this.reader = reader;
        }

        public static WordPlugin Create(Type t) {
            IWordDictionaryReader reader = Instantiate(t) as IWordDictionaryReader;
            WordPlugin plugin = new WordPlugin(reader);
            plugin.FillCommon(t);
            return plugin;
        }
        public IWordDictionary read(PathProvider provider) {
            string filename = Settings["file"] as string;
            if (filename == null) {
                return fillFileName(provider);
            }
            return readDic(filename);
        }

        public IWordDictionary fillFileName(PathProvider provider) {
            string found = provider(this);
            string filename = PathUtil.GetDictPath(Mask); //TODO fixme
            IWordDictionary dic = readDic(found);
            File.Copy(found, filename, true);
            Settings["file"] = filename;
            return dic;
        }

        private IWordDictionary readDic(string filename) {
            FileStream stream = File.OpenRead(filename);
            IWordDictionary dictionary = reader.read(stream);
            stream.Close();
            return dictionary;
        }
    }

    public class PluginNameComparer : IComparer<Plugin> {
        public int Compare(Plugin x, Plugin y) {
            return x.Name.CompareTo(y.Name);
        }
    }
}
